"""Property service for business logic (Synchronous)."""

from __future__ import annotations

from datetime import datetime
from typing import Optional

from sqlalchemy import select, func
from sqlalchemy.orm import Session

from ..models.property import Property
from ..schemas.property import PropertyCreate, PropertyUpdate, PropertyOut


class PropertyService:
    """Service for property management business logic (Synchronous)."""

    def __init__(self, db: Session):
        """Initialize service with database session."""
        self.db = db

    def create_property(self, property_data: PropertyCreate) -> PropertyOut:
        """
        Create a new property.

        Args:
            property_data: Property creation data

        Returns:
            Created property with ID
        """
        property_dict = property_data.model_dump()
        db_property = Property(**property_dict)

        self.db.add(db_property)
        self.db.commit()
        self.db.refresh(db_property)

        return PropertyOut.model_validate(db_property)

    def get_property(self, property_id: int) -> Optional[PropertyOut]:
        """
        Get property by ID.

        Args:
            property_id: Property ID

        Returns:
            Property if found, None otherwise
        """
        db_property = self.db.query(Property).filter(
            Property.id == property_id,
            Property.is_deleted == False
        ).first()

        if db_property:
            return PropertyOut.model_validate(db_property)
        return None

    def get_properties(
        self,
        skip: int = 0,
        limit: int = 20,
        community_name: Optional[str] = None,
        status: Optional[str] = None,
        min_price: Optional[int] = None,
        max_price: Optional[int] = None,
    ) -> tuple[list[PropertyOut], int]:
        """
        Get paginated list of properties with filters.

        Args:
            skip: Number of records to skip
            limit: Maximum number of records to return
            community_name: Filter by community name (partial match)
            status: Filter by property status
            min_price: Minimum rent price
            max_price: Maximum rent price

        Returns:
            Tuple of (property list, total count)
        """
        # Build query
        query = self.db.query(Property).filter(Property.is_deleted == False)

        # Apply filters
        if community_name:
            query = query.filter(Property.community_name.like(f"%{community_name}%"))
        if status:
            query = query.filter(Property.status == status)
        if min_price is not None:
            query = query.filter(Property.rent_price >= min_price)
        if max_price is not None:
            query = query.filter(Property.rent_price <= max_price)

        # Count total
        total = query.count()

        # Get paginated results
        properties = query.order_by(Property.created_at.desc()).offset(skip).limit(limit).all()

        return [PropertyOut.model_validate(p) for p in properties], total

    def update_property(
        self, property_id: int, property_data: PropertyUpdate
    ) -> Optional[PropertyOut]:
        """
        Update property by ID.

        Args:
            property_id: Property ID
            property_data: Property update data

        Returns:
            Updated property if found, None otherwise
        """
        db_property = self.db.query(Property).filter(Property.id == property_id).first()

        if not db_property:
            return None

        # Update fields
        update_data = property_data.model_dump(exclude_unset=True)
        for field, value in update_data.items():
            setattr(db_property, field, value)

        self.db.commit()
        self.db.refresh(db_property)

        return PropertyOut.model_validate(db_property)

    def delete_property(self, property_id: int, user_id: int) -> bool:
        """
        Soft delete property by ID.

        Args:
            property_id: Property ID
            user_id: User performing the deletion

        Returns:
            True if deleted, False if not found
        """
        db_property = self.db.query(Property).filter(Property.id == property_id).first()

        if not db_property:
            return False

        db_property.is_deleted = True
        db_property.deleted_at = datetime.utcnow()
        db_property.deleted_by = user_id
        self.db.commit()
        return True

    def restore_property(self, property_id: int) -> bool:
        """
        Restore soft-deleted property.

        Args:
            property_id: Property ID

        Returns:
            True if restored, False if not found or not deleted
        """
        db_property = (
            self.db.query(Property).filter(Property.id == property_id, Property.is_deleted).first()
        )

        if not db_property:
            return False

        db_property.is_deleted = False
        db_property.deleted_at = None
        db_property.deleted_by = None
        self.db.commit()
        return True

    def bulk_soft_delete(self, property_ids: list[int], user_id: int) -> dict[str, int]:
        """
        Bulk soft delete properties.

        Args:
            property_ids: List of property IDs to delete (max 50)
            user_id: User performing the deletion

        Returns:
            dict: {"success": count, "failed": count, "not_found": count}
        """
        if not property_ids:
            return {"success": 0, "failed": 0, "not_found": 0}

        success_count = 0
        not_found_count = 0
        deleted_at = datetime.utcnow()

        for property_id in property_ids:
            db_property = (
                self.db.query(Property)
                .filter(Property.id == property_id, Property.is_deleted == False)
                .first()
            )

            if not db_property:
                not_found_count += 1
                continue

            db_property.is_deleted = True
            db_property.deleted_at = deleted_at
            db_property.deleted_by = user_id
            success_count += 1

        self.db.commit()

        return {"success": success_count, "failed": 0, "not_found": not_found_count}

    def bulk_restore(self, property_ids: list[int]) -> dict[str, int]:
        """
        Bulk restore soft-deleted properties.

        Args:
            property_ids: List of property IDs to restore (max 50)

        Returns:
            dict: {"success": count, "failed": count, "not_found": count}
        """
        if not property_ids:
            return {"success": 0, "failed": 0, "not_found": 0}

        success_count = 0
        not_found_count = 0

        for property_id in property_ids:
            db_property = (
                self.db.query(Property)
                .filter(Property.id == property_id, Property.is_deleted)
                .first()
            )

            if not db_property:
                not_found_count += 1
                continue

            db_property.is_deleted = False
            db_property.deleted_at = None
            db_property.deleted_by = None
            success_count += 1

        self.db.commit()

        return {"success": success_count, "failed": 0, "not_found": not_found_count}

    def check_duplicate_room(
        self, community_name: str, room_number: str, exclude_id: Optional[int] = None
    ) -> bool:
        """
        Check if room number already exists in community.

        Args:
            community_name: Community name
            room_number: Room number
            exclude_id: Property ID to exclude from check (for updates)

        Returns:
            True if duplicate exists, False otherwise
        """
        query = self.db.query(Property).filter(
            Property.community_name == community_name, Property.room_number == room_number
        )

        if exclude_id:
            query = query.filter(Property.id != exclude_id)

        return query.first() is not None
